package org.datacoder.geocoding.datastructures.points

import org.datacoder.geocoding.datastructures.geoshapes.*
import org.datacoder.geocoding.datastructures.util.*
import org.datacoder.geocoding.jurisdiction.*

class Cells implements PointsWithinRectangleFinder {

    private GeoPoint usPoint
    private State alaska
    private State hawaii
    private CellsSubStructure lower48Cells
    private CellsSubStructure alaskaCells
    private CellsSubStructure hawaiiCells

    public Cells(Collection<Jurisdiction> jurisdictions){
        Set<State> lower48 = State.findAll()
        alaska = State.findByName("AK")
        hawaii = State.findByName("HI")
        if(alaska != null){
            lower48.remove(alaska)
        }
        if(hawaii != null){
            lower48.remove(hawaii)
        }
        Set<Jurisdiction> lower48Jurisdictions = new HashSet<Jurisdiction>(lower48)
        Set<Jurisdiction> alaskaJurisdictions = new HashSet<Jurisdiction>()
        Set<Jurisdiction> hawaiiJurisdictions = new HashSet<Jurisdiction>()
        if(alaska != null){
            alaskaJurisdictions.add(alaska)
        }
        if(hawaii != null){
            hawaiiJurisdictions.add(hawaii)
        }
        for(juris in jurisdictions){
            if(juris instanceof Country){
                usPoint = juris.toGeoPoint()
            }else if(juris instanceof State){
                continue
            }else if(juris instanceof County){
                if(((County)juris).state == alaska){
                    alaskaJurisdictions.add(juris)
                }else if(((County)juris).state == hawaii){
                    hawaiiJurisdictions.add(juris)
                }else{
                    lower48Jurisdictions.add(juris)
                }
            }else if(juris instanceof Municipality){
                if(((Municipality)juris).state == alaska){
                    alaskaJurisdictions.add(juris)
                }else if(((Municipality)juris).state == hawaii){
                    hawaiiJurisdictions.add(juris)
                }else{
                    lower48Jurisdictions.add(juris)
                }
            }else if(juris instanceof CongressionalDistrict){
                if(((CongressionalDistrict)juris).state == alaska){
                    alaskaJurisdictions.add(juris)
                }else if(((CongressionalDistrict)juris).state == hawaii){
                    hawaiiJurisdictions.add(juris)
                }else{
                    lower48Jurisdictions.add(juris)
                }
            }else if(juris instanceof SenatorialDistrict){
                if(((SenatorialDistrict)juris).state == alaska){
                    alaskaJurisdictions.add(juris)
                }else if(((SenatorialDistrict)juris).state == hawaii){
                    hawaiiJurisdictions.add(juris)
                }else{
                    lower48Jurisdictions.add(juris)
                }
            }else if(juris instanceof RepresentativeDistrict){
                if(((RepresentativeDistrict)juris).state == alaska){
                    alaskaJurisdictions.add(juris)
                }else if(((RepresentativeDistrict)juris).state == hawaii){
                    hawaiiJurisdictions.add(juris)
                }else{
                    lower48Jurisdictions.add(juris)
                }
            }else if(juris instanceof ZipCode){
                if(((ZipCode)juris).state == alaska){
                    alaskaJurisdictions.add(juris)
                }else if(((ZipCode)juris).state == hawaii){
                    hawaiiJurisdictions.add(juris)
                }else{
                    lower48Jurisdictions.add(juris)
                }
            }else if(juris instanceof VotingDistrict){
                if(((VotingDistrict)juris).county.state == alaska){
                    alaskaJurisdictions.add(juris)
                }else if(((VotingDistrict)juris).county.state == hawaii){
                    hawaiiJurisdictions.add(juris)
                }else{
                    lower48Jurisdictions.add(juris)
                }
            }
        }
        lower48Cells = new CellsSubStructure(lower48Jurisdictions, lower48)
        if(alaska != null){
            Set<Jurisdiction> alaskaSet = new HashSet<Jurisdiction>()
            alaskaSet.add(alaska)
            alaskaCells = new CellsSubStructure(alaskaJurisdictions, alaskaSet)
        }
        if(hawaii != null){
            Set<Jurisdiction> hawaiiSet = new HashSet<Jurisdiction>()
            hawaiiSet.add(hawaii)
            hawaiiCells = new CellsSubStructure(hawaiiJurisdictions, hawaiiSet)
        }
    }

    public Set<Jurisdiction> findPointsWithinRectangle(GeoRectangle gr){
        Set<Jurisdiction> jurisdictions = new HashSet<Jurisdiction>()
        jurisdictions.addAll(lower48Cells.findPointsWithinRectangle(gr))
        if(alaska != null){
            jurisdictions.addAll(alaskaCells.findPointsWithinRectangle(gr))
        }
        if(hawaii != null){
            jurisdictions.addAll(hawaiiCells.findPointsWithinRectangle(gr))
        }
        if(gr.containsGeoPoint(usPoint)){
            jurisdictions.add(usPoint.juris)
        }
        return jurisdictions
    }
	
}

